#
# file: $Id: templateParser.py 78 2010-08-17 00:42:53Z duboulay $
#
# Author: Doug du Boulay <boulay_d@chem.usyd.edu.au>
# Copyright (c) 2009, The University of Sydney
# All rights reserved.
#
# This software is distributed under the BSD license.
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. The name of the author may not be used to endorse or promote products
#    derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#
import sys
from string import atoi  
from xml import sax
from xml.sax import make_parser
import logging


# this is one of ours
from xml2dict import XMLDictionaryHandler, XMLMarshal
from dbConnect import *

DEBUG = 1+ 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 
DEBUG = 0


class Status:
    """ just a wrapper around eval/exec/sql results"""
    def __init__(self,success, result):
      self.success = success
      self.value = result


class TemplateParser:
    """class to read Bruker postgres database and 
    an ICAT xml template file and populate the template
    with data from the database."""

    def __init__(self):
        self._log = logging.getLogger('%s.%s' % 
               (__name__, self.__class__.__name__))
	self.dbcnx = None
        self.templateFile = None
        self.template = {}
	self.globalContext  =  None
        self.contextList = []
	self.currentContext = None
        self.ancestors = []
	self.genData = None
        self.injectData = None
        self.ctnode = None

    def initTemplate(self, file): 
         self.templateFile = file
	 p = make_parser()
         h = XMLDictionaryHandler()
         p.setContentHandler(h)
         p.parse(open(file))
         self.template = h.d
         if DEBUG & 1:
           self._log.debug("Template loaded from file: %s",file)

    def registerDBConnection(self, dbconnect): 
	self.dbcnx = dbconnect


    def applyTemplate(self, params): 
        if self.template == None:
            raise Exception, "No XML template supplied"
	self.globalContext  = params
        self.contextList.append(params)
	self.currentContext = self.contextList[-1]
        
        res = self.parseTemplate(self.template, None )
        if res.success:
          self.genData = res.value


    def parseTemplate(self, inNode, outParent,push=True): 
        """ inNode is not necessarily an XML element: value hash - 
        it maybe an attribute hash or a list of children or a string value too.
        """
        self.ctnode = inNode
        if type(inNode) == type({}):
          data = {}
          self.ancestors.append(data)
          for elem, value in inNode.items():
            if elem.find(u'map:')==0:
              if elem == u'map:key':  # only if a map attrib on icat element
                self.currentContext[value] =  self.globalContext[value]  # redundant
                continue
              res = self.evalMap(elem, value, self.currentContext,outParent) 
              if res.success:
                if res.value != None:   data[elem] = res.value
              else:                # failed to eval. Abort 
                #print  elem, value, res.value
                self.ancestors.pop()
                return Status(False,[{},res.value,[]]) # replace with dummy "node"
            else:
              data[elem] = None # so the kiddies know what their great grandparent was
               #  print elem
              res = self.parseTemplate(value,data)
              if res.success:
                data[elem] = res.value
              else:
                # hopefully a dummy result
                data[elem] = res.value
                pass #????????????
          self.ancestors.pop()
          data = self.postFixElementHash(data);
          return Status(True,data)
        elif type(inNode) == type([]):    # a list of child elements as hashes?
          data = []
          self.ancestors.append(data) 
          if push:
            ctxt =  self.cloneCtxt()
          for value in inNode:
               res = self.parseTemplate(value,data)
               if res.success:
                 if res.value != None:
                   data.append(res.value) 
                 #else:
                 #  parent[1] = '?'
               else:   # possible subsequent tests may depend on this result
                 self.ancestors.pop()
                 if push:
                   self.popCtxt()
                 return res
          if push:
            self.popCtxt()
          self.ancestors.pop()
          return Status(True,data)
        elif type(inNode) == type(''):
          return Status(True,inNode)
        elif type(inNode) == type(u''):
          return Status(True,inNode)

        raise Exception, "Unexpected node type", inNode


    def postFixElementHash(self, data):
        """We have to postfix the generated node tree to be as
           simple as possible and still consistent with a generated
           XMLDictionaryHandler() XML data structure"""
           
        mapped = 0
        nall = 0
        for elem, value in data.items():
            if elem.find(u'map:')==0:
                mapped += 1
            else: 
                nall += 1
        if not mapped:  
            return data
        #
        #check = {}
        check = None
#        print "woot " , data.keys(), mapped, nall
        if mapped + nall == mapped:
            if mapped == 1: 
              p = self.ancestors[-1]
              gp = self.ancestors[-2]
              ggp = self.ancestors[-3]
#              print "no way!" , type(p), type(gp)
              if type(p) == type([]):
#                print ggp
#                print gp
#                print p
#                print data
                if type(gp) == type([]):
                   #print "no way!" , len(gp), gp[1]
                   if len(gp)>=2 and gp[1] == '':  # no data added yet, so just 2!

                      for elem, value in data.items():  # there is only one
                         if elem== u'map:attribute':   #  purge  map:attrib 
                           for att, val in data[elem].items(): # there is only one
                             gp[0][att] =val
                           return check 
                         if type(value) == type(''):
                           gp[1] = value 
                           #print gp
                         elif type(value) == type([]):
                           p.extend(value)  # append  list of elements to existing ... 
                           if DEBUG & 8:
                               self._log.debug("Extending existing list")
                         else:
                           gp[1] = value 
                           #print " what the?" , value, " ", type(value)
#                      print "result: ", gp
                      return check 
                   elif len(gp)==2 : # 
                      self._log.debug("whats going on? %s %s", str(gp),str(data))

                      for elem, value in data.items():  # there is only one
                         if type(value) == type(''):
                             p.append(value) # append  string to child list
                         elif type(value) == type([]):
                           p.extend(value)  # append  list of elements to existing ... 
                           if DEBUG & 8:
                               self._log.debug("Extending existing list")
                         else:
                           gp[1] = value 
                           self._log.debug("what the? %s %s", str(value),str(type(value)))
                      self._log.debug("result: ", str(gp))
                      return check 
                   else:
                      for elem, value in data.items():  # there is only one
                         check = value 
                         return check
                else:
                  self._log.error("expected grandparent to be a list")
              else:
                self._log.error("expected parent to be a list")
            else:
              # ummm not sure how this could  happen
              p = self.ancestors[-1]
              gp = self.ancestors[-2]
            
        
        self._log.error("Unexpected  xml hierarchy mangling  condition for: %s" ,
                          data)
        return data
            




    def evalMap(self, elem, value, context,parent): 
      if elem.find(u'map:')!=0:
	raise Exception, "template parsing error on: " + elem + ": " + value + ": " + key
      func = elem[4:]
      if func == u'sql':    # this is a terminal/leaf node  value is a list
        res = self.evalSQL(elem, value, context, parent) 
        return res
      elif func == u'py':    # this is a terminal/leaf node  value is a list
        res = self.evalPy(elem, value, context, parent) 
        return res
                                # this is not a terminal leaf node
      elif func == u'for-each':  # this has to recurse like  parseTemplate   
        res = self.__foreach(elem, value, context, parent) 
        return res
                                # this is not a terminal leaf node
      elif func == u'if':  # this has to recurse like  parseTemplate   
        res = self.__if(elem, value, context, parent) 
        return res
                                # this is not a terminal leaf node
      elif func == u'attribute':  # this has to recurse like  parseTemplate   
        res = self.__attribute(elem, value, context, parent) 
        return res
      elif func == u'element':  # this has to recurse like  parseTemplate   
        res = self.__element(elem, value, context, parent) 
        return res

      self._log.warning("unknown map function %s : %s :" ,func ,value )
      return Status(False,None)


    def evalSQL(self, elem, value, context, parent): 
        if self.dbcnx == None:
            self._log.debug("%s %s", self.ctnode, context)
            self.dumpMap(context)
            raise Exception, "No database connection"
        try:
            val = self.contextSubstitute(value[1], context)#apply substitutions 
        except Exception, msg:
	  if u'map:none' in value[0] and value[0][u'map:none'] == 'skip':
            if u'map:key' in value[0]: 
               context[value[0][u'map:key']] = None
            return Status(True,None)
          self._log.debug("%s %s", self.ctnode, context)
          raise Exception, msg

	try:
 	    res = self.dbcnx.query(val) # [ attribs, text, sub elements ]
        except DBConnectSQLSyntaxException, msg:
            self._log.debug("%s %s", self.ctnode, context)
            self._log.debug(msg)
            raise DBConnectSQLSyntaxException, msg
        except DBConnectSQLResultException, msg:
            self._log.debug("%s %s", self.ctnode, context)
            self._log.debug(msg)
            raise DBConnectSQLResultException, msg
          
        ret = None
        if res.nfields <= 0:  
	  if  u'map:key' in value[0] and \
              u'map:none' in value[0] and value[0][u'map:none'] == 'skip':
            context[value[0][u'map:key']] = None
            return Status(True,None)
             
          gggp = self.ancestors[-4]
          if u'string_value' in gggp:
              return Status(False, '?')  #########   this is a CIF thing ....
          elif u'numeric_value' in gggp:
              return Status(False, 'N/A' ) #########  this is an oracle thing ....
                                   #########  hope it doesn't kill anything else!
          return Status(False,'N/A')  # query failed to return a result 

	if  u'map:key' in value[0]:                 #  add value to context 
          if res.ntuples == 1 and  res.nfields == 1:  # scalar
            if res.getvalue(0,0) == None: 
              if u'map:none' in value[0]:
                if value[0][u'map:none'] == 'break':
                   #   elegant stop on this item, but continue
                  gggp = self.ancestors[-4]
                  if u'string_value' in gggp:
                      return Status(False, '?')  #########   this is a CIF thing ....
                  elif u'numeric_value' in gggp:
                      return Status(False, 'N/A' ) #########  this is an oracle thing ....
                                           #########  hope it doesn't kill anything else!
                  return Status(False,'N/A')  # query failed to return a result 
                if value[0][u'map:none'] == 'skip':
                  context[value[0][u'map:key']] = None    ###
                  return Status(True,None)  # success, but no result
                raise DBConnectSQLSyntaxException, \
            "don't know what to do with map:none= "+ value[0][u'map:none']  
              #else, come what may ...
            context[value[0][u'map:key']] = res.getvalue(0,0)
            self._log.debug(res.getvalue(0,0) )
          elif res.nfields == 1:     # simple list
            l = []
            for i in range(res.ntuples):
              for j in range(res.nfields):
                l.append(res.getvalue(i, j))
            if len(l)<=0:
              if u'map:none' in value[0] and value[0][u'map:none'] == 'break':
                #   elegant stop on this item, but continue
	        gggp = self.ancestors[-4]
                if u'string_value' in gggp:
                  return Status(False, '?')  #########   this is a CIF thing ....
                elif u'numeric_value' in gggp:
                  return Status(False, 'N/A' ) #########  this is an oracle thing ....
                                       #########  hope it doesn't kill anything else!
                return Status(False,'N/A')  # query failed to return a result 
            context[value[0][u'map:key']] = l
          else:                      # an array
            l = []
            for i in range(res.ntuples):
              l.append([])
              for j in range(res.nfields):
                l[i].append(res.getvalue(i, j))
            if len(l)<=0:
              if u'map:none' in value[0] and value[0][u'map:none'] == 'break':
                #   elegant stop on this item, but continue
	        gggp = self.ancestors[-4]
                if u'string_value' in gggp:
                  return Status(False, '?')  #########   this is a CIF thing ....
                elif u'numeric_value' in gggp:
                  return Status(False, 'N/A' ) #########  this is an oracle thing ....
                                       #########  hope it doesn't kill anything else!
                return Status(False,'N/A')  # query failed to return a result 
            context[value[0][u'map:key']] = l
          return Status(True,None)  # success, but no result

        # end of map:key 

        else:                      # this is "the" result.    
          if res.ntuples == 1 and  res.nfields == 1: # scalar
            ret = res.getvalue(0,0)
            if ret == None or ret == "n/a" or ret == "N/A" or ret == '': 
              #  Handling no result  is target specific
              #  somehow this has to be outsourced  to be general.
              #  print  gggp, elem
              gggp = self.ancestors[-4]
              if u'string_value' in gggp:
                  ret = "?"        #########   this is a CIF thing ....
              elif u'numeric_value' in gggp:
                  ret = "N/A"      #########   this is an oracle thing ....
                                   #########  hope it doesn't kill anything else!
              else: ret = '?'
            else: 
	      #convert numbers to strings -  strings remain strings
              ret =  str(ret)
          else:
            ret = []
            for i in range(res.ntuples):
              ret.append([])
              for j in range(res.nfields):
                ret[i].append(res.getvalue(i, j))
        res.clear()
        if DEBUG & 8:
          self._log.debug("sql: %s : %s" , value , ret)
          self._log.debug("--------------- %s" , context)
        return Status(True,ret)  # success, and a result

    def my_os_path_basename(self, filename): 
        if not filename: return filename
        if type(filename) != type(''):
            raise Exception , "error getting basename from non-string"
        if len(filename)<2: return filename
        if filename[1] == ":":
             filename = filename[2:]
        filename = filename.replace("\\", "/")
        import os 
        return os.path.origbasename(filename)

    def evalPy(self, elem, value, context, parent): 
        import os
        # futz with basename because we are on unix but looking at windows paths
        os.path.__setattr__('origbasename',  os.path.basename)
        if os.name == 'posix':
          os.path.__setattr__('basename',  self.my_os_path_basename)
        
        context['InjectXML'] = self.injectXML
        context['os'] = os   # apparently this is very dangerous!
        # because anyone could add a python expression to the template 
        # to trash the disk or something.
        try:
          ret = eval(value[1], globals(), context) 
          
          if DEBUG & 8:
            self._log.debug("py-eval: %s : %s" , value , ret)
	  if  u'map:key' in value[0]:                 #  add value to context 
            context[value[0][u'map:key']] =  ret
            ret = None # success, but no result
#ddb        #ret = str(ret)
          os.path.__setattr__('basename',  os.path.origbasename)
          return Status(True,ret)  # success, and a result
        except  SyntaxError, msg: 
          pass
        except  Exception, msg:
            self._log.error(msg)
            self._log.error("py-eval: %s :" , value )
            self.dumpMap(context)
	    import sys, traceback
            exc_type, exc_value, exc_traceback = sys.exc_info()
            slist = traceback.format_tb(exc_traceback)
            self._log.error(str(slist[-1]))
            raise 
            #percolate to the top
            #from sys import exit
            #exit()

        try:
	  if u'map:key' in value[0]: 
            self._log.error("py-exec: %s :" , value )
            self.dumpMap(context)
            self._log.critical("Template Error. Cannot apply map:key to an python 'exec' expression." )
            self._log.critical("It only works for 'eval' expressions.")
            raise Exception, "Fatal Exception Template error FIXUPmsg"
            #from sys import exit
            #exit()
          exec value[1] in globals(), context
          if DEBUG & 8:
            self._log.error("py-exec: %s" , value )
          if  self.injectData != None:
            tmp = self.injectData
            self.injectData = None
            if DEBUG & 8:
              self._log.error("Yo-katta!")
            os.path.__setattr__('basename',  os.path.origbasename)
            return Status(True,tmp) 
          os.path.__setattr__('basename',  os.path.origbasename)
          return Status(True,None)  # success, and a result
          

        except  Exception, msg: 
          self._log.error(self.ctnode)
          self.dumpMap(context)
          self._log.error("py-exec: %s %s" , msg.__class__ , msg)
          self._log.error("premature termination")
          import traceback
          import sys
          traceback.print_exc(file=sys.stdout)
          raise Exception, msg
          #sys.exit(1) 
          #return Status(False,None)  # success, and a result
        
        os.path.__setattr__('basename',  os.path.origbasename)
        # um, did it work?


    def __foreach(self, elem, value, context, parent): 
      """ The idea is to remove all trace of this "map:for-each" node from the target tree
          and replace it with the results of its children.
          This is gunna fail if the map:from is, say a SQL 1 row tuple
          rather than a multirow list!  bummer! """

      # get the foreach  "list"
      if  u'map:from' in value[0]:                 #  add value to context 
        _listName = value[0][u'map:from']
        try:
            _from = eval(_listName, globals(), context) 
        except  Exception, msg:
            
            self.dumpMap(context)
            self._log.error(msg)
            self._log.error("py-eval: %s" , value )
            #raise Exception, msg
            #percolate to the top
            self._log.critical("It only works for 'eval' expressions.")
            raise Exception, "Fatal Exception Template error FIXUPmsg"
            #from sys import exit
            #exit()
          
      # make a list out of it so we can iterate
      if _from== None:
        _from =  []
      elif type(_from) != type([]) and type(_from) != type(()):
        _from =  [_from]

      # get the foreach  "key"
      if  not u'map:key' in value[0]:                 #  add value to context 
          self.dumpMap(context)
          raise Exception, "map:foreach loop with no iterator 'key'"
      _iterName = value[0][u'map:key']
      
#      print "\nancestor ",self.ancestors
#      print "\nparent ",parent
      #   self.ancestors.append(data)
      ctxt = self.cloneCtxt()   # make a copy of current and push on the stack
#      print elem
#      print value
      for val in _from:
          ctxt[_iterName] = val # technically this is self.currentContext
          #print "context1" ,type(context),
          #self.dumpMap(context)
          #print "context2" ,
          #self.dumpMap(self.currentContext) 
#          print type(elem)
#          print "hello", val
          res = self.parseTemplate(value[2],parent)  # value2 is a list of child nodes
          if res.success:
             if res.value != None:
                for v in res.value:   # for each result of the child list
                  parent.append(v)    # append as a child of our (for-each) parent 
          else:   # no children so ?
                  # should we break the loop?
                  # or throw an exception or what?            
             break
      ctxt = self.popCtxt()   # make a copy of current and push on the stack

      #return Status(False,[{},"",[]]) # replace with dummy "node"
      return Status(True,None) #  already injected
        
	  
    def __if(self, elem, value, context, parent): 
      """ The idea is to remove all trace of this "map:for-each" node from the target tree
          and replace it with the results of its children.
          This is gunna fail if the map:from is, say a SQL 1 row tuple
          rather than a multirow list!  bummer! """

      # get the if  "test"
      if  not u'map:test' in value[0]:                 #  add value to context 
          raise Exception, "map:if with no test? that ain't right!"
      _test = value[0][u'map:test']
      
      try:
          ret = eval(_test, globals(), context) 
          
          if DEBUG & 16:
            self._log.debug("map:if: %s : %s" , _test , ret)
      except  Exception, msg:
          self._log.error(msg)
          self._log.error("map:if: %s " , value )
          self.dumpMap(context)
          raise Exception, msg

      if not ret:    # doesn't evaluate true in python sense
         return Status(True,None) # successfully evaluated but no result
#      print "\nancestor ",self.ancestors
#      print "\nparent ",parent
      #   self.ancestors.append(data)
#      print elem
#      print value
#          print type(elem)
#          print "hello", val
#ddb      ctxt = self.cloneCtxt()   # make a copy of current and push on the stack
      res = self.parseTemplate(value[2],parent,False) # value2 is a list of child nodes
      # retain current context
      if res.success:
          if res.value != None:
             for v in res.value:   # for each result of the child list
               parent.append(v)    # append as a child of our (for-each) parent 
      else:   # no children so ?
                  # should we break the loop?
                  # or throw an exception or what?            
          pass
#ddb      ctxt = self.popCtxt()   # pop context from stack
      return Status(True,None) #  already injected



    def __element(self, elem, value, context, outParent): 
      """ The idea is to remove all trace of this "map:element" node from the target tree
          and replace it with the results of its children.
          This is gunna fail if the map:from is, say a SQL 1 row tuple
          rather than a multirow list!  bummer! """

      # get the if  "test"
      if  not u'map:name' in value[0]:                 #  add value to context 
          raise Exception, "map:element with no attribute name!"
      _name = value[0][u'map:name']
      
      try:
          ret = eval(_name, globals(), context) 
          
          if DEBUG & 16:
            self._log.debug("map:element: %s :  %s" , _name , ret)
      except  Exception, msg:
          self._log.error(msg)
          self._log.error("map:element: %s " , value )
          self.dumpMap(context)
          raise Exception, msg

      if not ret:
          raise Exception, "map:element generates null name!"

      ctxt = self.cloneCtxt()   # make a copy of current and push on the stack
#      global DEBUG
#      savedebug = DEBUG
#      DEBUG = 1+ 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 

#      element = {ret: value } # new output parent XML element node
      children = []
      element = {ret: [{},'',children] } # new output parent XML element node
      self.ancestors.append([]) #  otherwise map:py children don't apply
      # parseTemplate(self, inNode, outParent,push=True)
      res = self.parseTemplate(value[2],children,False) # value2 is a list of child nodes
      self.ancestors.pop()
      outParent.append(element)
      # The logic here defies me, but it seems to work for simple case ....
      """
      print "ancestor ",self.ancestors[-3:]
      print "parent " , outParent
      print "elem in" , elem
      print "element " , element
      print "element out" , ret
      print "children" , children
      """
      if res.success:
          if res.value != None:
             for v in res.value:   # for each result of the child list
               # print "append " , v
               children.append(v)    # append as a child of our ('element') parent 
      else:   # no children so ?
                  # should we break the loop?
                  # or throw an exception or what?            
          pass
      ctxt = self.popCtxt()   # pop context from stack
#      DEBUG = savedebug
      #return Status(True,element) #  already injected
      return Status(True,None) #  already injected


    def __attribute(self, elem, value, context, parent): 
      """ The idea is to remove all trace of this "map:attribute" node from the target tree
          and replace/add a new attribute in its parent - with a 
          value taken from result of its children. """

      # get the if  "test"
      if  not u'map:atname' in value[0]:                 #  add value to context 
          self._log.error("map:attribute with no attribute name ")
          raise Exception, msg
      _name = value[0][u'map:atname']
      
      ctxt = self.cloneCtxt()   # make a copy of current and push on the stack
      dummy = [{},"",value[2]]   # value2 is a list of child nodes
      res = self.parseTemplate(dummy,parent)
      ret = None
      if res.success:
          if res.value != None:
             sbuf = [res.value[1]] # pull out string val
             for v in res.value[2]: # for each hash in the child list
               self._log.debug(res.value)
               if v:    # not empty dict
                 key=v.keys()[0]
                 sbuf.append(v[key][1]) # get string component
             ret =  {_name : "".join(sbuf) }
      else:  # no children so ?
             # should we break the loop?
             # or throw an exception or what?            
          pass
      ctxt = self.popCtxt()   # pop context from stack
      return Status(True,ret) #  postFix this baby




    def dumpMap(self,map): 
        self._log.debug("CONTEXT DUMP")
        for  key  in map.keys():
           if key!="H5FILE":
              self._log.debug("  %s %s", key, str(map[key]) )
           else: 
              self._log.debug("  %s --SUPPRESSED--", key )


    def cloneCtxt(self): 
        ctxt = {}
        for  key, val  in self.contextList[-1].items():
	    ctxt[key] = val
        self.contextList.append(ctxt)
	self.currentContext = ctxt
        return ctxt

    def popCtxt(self): 
        self.contextList.pop()
	self.currentContext = self.contextList[-1]

    def contextSubstitute(self, string, context ): 
        if DEBUG & 2:
            self._log.debug("%s ======== %s" ,string, context)
	return string % context

    def injectXML(self, content ): 
        if DEBUG & 16:
          self._log.debug("injected %s" ,content)
        if self.injectData == None:
            self.injectData= []

	p = make_parser()
        h = XMLDictionaryHandler()
        p.setContentHandler(h)
        q = sax.parseString(content,h)
        if DEBUG & 64:
            import pprint
            pprint.pprint(h.d, indent=1)
        self.injectData.append(h.d)
       



if __name__ == '__main__':

    parser = TemplateParser()
    parser.initTemplate(ICATTEMPLATE)
    
    try: 
        params = {}  # null params 
        parser.applyTemplate(params)  
    except Exception, msg:
	if inp[0] != 'b':
          print msg
          sys.exit(1) 

    fname = ICATTEMPLATE + ".out"


    if DEBUG & 32:
        if parser.genData != None:
            import pprint
            pprint.pprint(parser.genData, indent=1)

    if parser.genData != None:
       from xml.sax.saxutils import XMLGenerator
       from xml2dict import BinXMLSAXParser
       p = BinXMLSAXParser()
       p.d = parser.genData
       p.setContentHandler(XMLGenerator(open(fname,'w') ))
       p._cont_handler.startDocument()
       p.__parse__(parser.genData)
       p._cont_handler.endDocument()
    print fname

    parser.disconnect()
